﻿// -- MVC4WPF
// -- Copyright © 2009 Information Control Corporation
// -- Revision History:
// -- Version 0.9.0.0 First codeplex release  - Stephen Giffin
// -- Version 1.0.0.0 Added IDesignLoader support and an abstract method to load the data at the consuming dataclass level. - Stephen Giffin
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace MVC4WPF
{
    /// <summary>
    /// Base class that implements the INotifyChanged and INotifyChanging events from the System.ComponentModel namespace
    /// Along with the helper methods used to On the related changed and changing events.
    /// </summary>
    public abstract class DataNotifyBase : INotifyPropertyChanged, INotifyPropertyChanging,IDesignLoader
    {
        #region Constructor

        /// <summary>
        /// Base class constructor that can only be called from the implementing class that inherits this base constructor
        /// </summary>
        protected DataNotifyBase()
        {
            //Intentinally blank
        }

        #endregion

        #region Implemention of Interface - INotifyPropertyChanged

        #region Implementation of event - PropertyChanged

        /// <summary>
        /// Local variable that is the event handler for the event 'PropertyChanged'.
        /// </summary>
        private PropertyChangedEventHandler _propertyChanged;

        /// <summary>
        /// Local variable that is the lock object for the event 'PropertyChanged', this is included for thread safety.
        /// </summary>
        private object _propertyChangedEventLock = new object();

        /// <summary>
        /// Subscribers to this event will be notified when a property has been changed, and the name of the changed property.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged
        {
            add
            {
                lock (_propertyChangedEventLock)
                {
                    _propertyChanged += value;
                }
            }

            remove
            {
                if (_propertyChangedEventLock != null)
                {
                    lock (_propertyChangedEventLock)
                    {
                        _propertyChanged -= value;
                    }
                }
            }
        }

        #endregion

        #region Helper methods for PropertyChanged

        /// <summary>
        /// Helper method that will On the 'PropertyChanged' event if there are any subscribers. This method will invoke the event with a standard invoke.
        /// </summary>
        /// <param name="sender">The source caller of the event.</param>
        /// <param name="e">The event arguments to be Ond with the event.</param>
        protected void OnPropertyChangedEvent(object sender, PropertyChangedEventArgs e)
        {

            if (_propertyChanged != null)
            {
                _propertyChanged.Invoke(sender, e);
            }
        }

        /// <summary>
        /// Helper method that will release the resources for the event "PropertyChanged"
        /// </summary>
        private void ReleasePropertyChangedEvent()
        {
            _propertyChanged = null;
            _propertyChangedEventLock = null;
        }

        /// <summary>
        /// This will alert all subscribers to the property changed event that a property has changed.
        /// </summary>
        /// <param name="propertyName">Name of the property that has changed.</param>
        protected void OnPropertyChanged(string propertyName)
        {
            this.OnPropertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        #endregion

        #region Implementation of Interface - INotifyPropertyChanging

        #region Implementation of event - PropertyChanging

        /// <summary>
        /// Local variable that is the event handler for the event 'PropertyChanging'.
        /// </summary>
        private PropertyChangingEventHandler _propertyChanging;

        /// <summary>
        /// Local variable that is the lock object for the event 'PropertyChanging', this is included for thread safety.
        /// </summary>
        private object _propertyChangingEventLock = new object();

        /// <summary>
        /// Subscribers to this event will be notified when a property is about to be changed, and the name of the changing property. 
        /// This is not a cancable event.
        /// </summary>
        public event PropertyChangingEventHandler PropertyChanging
        {
            add
            {
                lock (_propertyChangingEventLock)
                {
                    _propertyChanging += value;
                }
            }

            remove
            {
                if (_propertyChangingEventLock != null)
                {
                    lock (_propertyChangingEventLock)
                    {
                        _propertyChanging -= value;
                    }
                }
            }
        }

        #endregion

        #region Helper methods for PropertyChanging

        /// <summary>
        /// Helper method that will On the 'PropertyChanging' event if there are any subscribers. This method will invoke the event with a standard invoke.
        /// </summary>
        /// <param name="sender">The source caller of the event.</param>
        /// <param name="e">The event arguments to be Ond with the event.</param>
        protected void OnPropertyChangingEvent(object sender, PropertyChangingEventArgs e)
        {
            if (_propertyChanging != null)
            {
                _propertyChanging.Invoke(sender, e);
            }
        }

        /// <summary>
        /// Helper method that will release all resources used for the PropertyChanging event.
        /// </summary>
        private void ReleasePropertyChangingEvent()
        {
            _propertyChanging = null;
            _propertyChangingEventLock = null;
        }

        /// <summary>
        /// This will alert all subscribers to the PropertyChanging event that a property is about to change.
        /// </summary>
        /// <param name="propertyName">The name of the property that is about to change.</param>
        protected void OnPropertyChanging(string propertyName)
        {
            this.OnPropertyChangingEvent(this, new PropertyChangingEventArgs(propertyName));
        }

        #endregion

        #endregion

        #region IDesignLoader Members

        /// <summary>
        /// Loads data when the data class is attached for design time supprt.
        /// </summary>
        void IDesignLoader.LoadDesignData()
        {
            //Calls the create method to create and load the data class
            CreateDesignData();
        }

        /// <summary>
        /// Abstract method implemented on the consuming class to create design time data.
        /// </summary>
        protected abstract void CreateDesignData();


        #endregion
    }
}

